//
// $Id$

package com.chuhay.elemwar;

import java.awt.Point;
import java.util.ArrayList;
import java.util.HashMap;

import static com.chuhay.elemwar.ElemWarConstants.*;

import com.chuhay.elemwar.ElemWarObject.Hex;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.crowd.util.CrowdContext;

import com.threerings.parlor.game.client.GameController;
import com.threerings.parlor.turn.client.TurnGameController;
import com.threerings.parlor.turn.client.TurnGameControllerDelegate;

import com.threerings.toybox.util.ToyBoxContext;
import com.threerings.util.Name;

/**
 * Manages the client side mechanics of the game.
 */
public class ElemWarController extends GameController implements TurnGameController {

   /** Our game panel. */
   protected ElemWarPanel _panel;

   /** Our game distributed object. */
   protected ElemWarObject _gameobj;

   protected TurnGameControllerDelegate _turndel;

   protected ElemWarLogic _logic;

   protected ArrayList <HexSprite> validMoves;

   protected int myType;

   public ElemWarController () {
      super();

      addDelegate(_turndel = new TurnGameControllerDelegate(this));

      validMoves = new ArrayList <HexSprite>(8);
   }

   public void hexClicked (Point pt) {
      // If not my turn, ignore click
      if (myType == _gameobj.getPlayerIndex(_gameobj.turnHolder)) {
         Point hexPoint = _panel._bview.getHexCenterForPoint(pt);

         // No hex clicked, do nothing
         if (hexPoint != null) {
            HexSprite clickedHex = null;
            HexSprite selectedHex = _panel._bview.selectedHex;

            // Find the hex that was clicked
            for (HexSprite hex : _panel._bview._hexes.values().toArray(new HexSprite [0])) {
               clickedHex = hex;
               if (hex._hex.y == hexPoint.y && hex._hex.x == hexPoint.x) {
                  break;
               }
               clickedHex = null;
            }

            // If a hex was actually clicked, 
            if (clickedHex != null) {
               // Determine move validity
               switch (_logic.getMoveValidity(clickedHex._hex, (selectedHex != null ? selectedHex._hex : null), myType, false)) {
               case VALID_VALID_MOVE:
                  // Move is valid, move the piece
                  _gameobj.manager.invoke("movePiece", _panel._bview.selectedHex._hex.hexID, clickedHex._hex.hexID);
                  break;
               case VALID_VALID_SELECT:
                  // We selected a piece we control other than the selected one, select this new one
                  _panel._bview.selectedHex = clickedHex;
                  _panel._bview.selectedHex._hex.selected = SELECT_SELECTED;
                  _panel._bview.selectedHex.invalidate();
                  // *** NOTE: This case falls through!!! ***
               case VALID_VALID_DESELECT:
                  // If hex selected, deselect it
                  if (selectedHex != null) {
                     selectedHex._hex.selected = SELECT_UNSELECTED;
                     selectedHex.invalidate();
                  }
                  if (clickedHex != selectedHex) {} else {
                     // If we did click the selected hex, set selectedHex to null
                     _panel._bview.selectedHex = null;
                  }

                  // We selected or deselected a hex, update valid hexes
                  setValidMoves(_panel._bview.selectedHex);
                  break;
               case VALID_INVALID:
                  // No valid move was chosen, ignore this click
                  break;
               }
            }
         }
      }
   }

   // Highlights valid moves for the selected hex
   protected void setValidMoves (HexSprite clickedHex) {
      // Get reference to the HexSprite list
      HashMap <Comparable, HexSprite> sprites = _panel._bview._hexes;
      HexSprite sprite;
      boolean adjPiece = false;

      // Always clear the current valid move list
      for (HexSprite hex : validMoves) {
         if (hex != null) {
            if (hex != _panel._bview.selectedHex) {
               hex._hex.selected = SELECT_UNSELECTED;
               hex.invalidate();
            }
         }
      }
      validMoves.clear();

      // If piece wasn't clicked, don't set any valid moves
      if (clickedHex == null) { return; }

      // Get the possible moves for the clicked piece
      Hex [][] possibleHexes = _logic.getPossibleMoves(_panel._bview.selectedHex._hex, myType);
 
      // For each pair of moves, add to valid moves if valid
      if (possibleHexes[0][0] != null) {
         sprite = sprites.get(possibleHexes[0][0].hexID);
         if (sprite._hex.pieceID == -1)
            // Hex is empty, add it
            validMoves.add(sprite);
         else
            // Hex is not empty, set flag
            adjPiece = true;
      }
      if (possibleHexes[1][0] != null) {
         sprite = sprites.get(possibleHexes[1][0].hexID);
         // If hex exists, is empty, and the adjacent hex has a piece, add it
         if (sprite != null && sprite._hex.pieceID == -1 && adjPiece)
            validMoves.add(sprite);
      }

      adjPiece = false;
      if (possibleHexes[0][1] != null) {
         sprite = sprites.get(possibleHexes[0][1].hexID);
         if (sprite != null)
            if (sprite._hex.pieceID == -1)
               validMoves.add(sprite);
            else
               adjPiece = true;
      }
      if (possibleHexes[1][1] != null) {
         sprite = sprites.get(possibleHexes[1][1].hexID);
         if (sprite != null && sprite._hex.pieceID == -1 && adjPiece)
            validMoves.add(sprite);
      }

      adjPiece = false;
      if (possibleHexes[0][2] != null) {
         sprite = sprites.get(possibleHexes[0][2].hexID);
         if (sprite != null)
            if (sprite._hex.pieceID == -1)
               validMoves.add(sprite);
            else
               adjPiece = true;
      }
      if (possibleHexes[1][2] != null) {
         sprite = sprites.get(possibleHexes[1][2].hexID);
         if (sprite != null && sprite._hex.pieceID == -1 && adjPiece)
            validMoves.add(sprite);
      }

      adjPiece = false;
      if (possibleHexes[0][3] != null) {
         sprite = sprites.get(possibleHexes[0][3].hexID);
         if (sprite != null)
            if (sprite._hex.pieceID == -1)
               validMoves.add(sprite);
            else
               adjPiece = true;
      }
      if (possibleHexes[1][3] != null) {
         sprite = sprites.get(possibleHexes[1][3].hexID);
         if (sprite != null && sprite._hex.pieceID == -1 && adjPiece)
            validMoves.add(sprite);
      }

      for (HexSprite hex : validMoves) {
         if (hex != null) {
            hex._hex.selected = SELECT_VALID;
            hex.invalidate();
         }
      }
   }

   /**
    * Requests that we leave the game and return to the lobby.
    */
   public void backToLobby () {
      _ctx.getLocationDirector().moveBack();
   }

   @Override
   // from PlaceController
   public void willEnterPlace (PlaceObject plobj) {
      super.willEnterPlace(plobj);

      // Get a casted reference to our game object
      _gameobj = (ElemWarObject) plobj;

      // Set player piece type
      myType = _gameobj.getPlayerIndex(((ToyBoxContext) _ctx).getUsername());

      // Create instance of logic class
      _logic = new ElemWarLogic(_gameobj);
   }

   @Override
   // from PlaceController
   public void didLeavePlace (PlaceObject plobj) {
      super.didLeavePlace(plobj);

      // clear out our game object reference
      _gameobj = null;
   }

   @Override
   // from PlaceController
   protected PlaceView createPlaceView (CrowdContext ctx) {
      _panel = new ElemWarPanel((ToyBoxContext) ctx, this);
      return _panel;
   }

   @Override
   // from GameController
   protected void gameDidStart () {
      super.gameDidStart();
   }

   @Override
   // from GameController
   protected void gameDidEnd () {
      super.gameDidEnd();

      // if we are the winner of the game, display some animated text
      // informing us of this fact
      ToyBoxContext tctx = (ToyBoxContext)_ctx;
      String message = (!_gameobj.isDraw() && _gameobj.isWinner(myType)) ?
          "m.you_win" : "m.game_over";
      _panel._bview.displayFloatingText(tctx.xlate("elemwar", message));
   }

   public void turnDidChange (Name arg0) {}
}
